import { _decorator, Component, EventTouch, Input, input, instantiate, Node, Prefab, SpriteFrame, UITransform, Vec2 } from 'cc';
import DataManager from '../Global/DataManager';
import { JoyStickManager } from '../UI/JoyStickManager';
import { ResourceManager } from '../Global/ResourceManager';
import { ActorManager } from '../Entity/Actor/ActorManager';
import { EventEnum, PrefabPathEnum, TexturePathEnum } from '../Enum';
import { ApiMsgEnum, EntityTypeEnum, IClientInput, IMsgServerSync, InputTypeEnum } from '../Common';
import { BulletManager } from '../Entity/Bullet/BulletManager';
import { ObjectPoolManager } from '../Global/ObjectPoolManager';
import { NetworkManager } from '../Global/NetworkManager';
import EventManager from '../Global/EventManager';
const { ccclass, property } = _decorator;

@ccclass('BattleManager')
export class BattleManager extends Component {

    private stage: Node;
    private ui: Node;

    private shouldUpdate = false;
    onLoad() { }

    async start() {
        this.clearGame()
        await Promise.all([this.connectServer(), this.loadRes()])

        // this.initGame()
    }


    initGame() {
        DataManager.Instance.jm = this.getComponentInChildren(JoyStickManager);
        this.initMap();
        this.shouldUpdate = true;
        EventManager.Instance.on(EventEnum.ClientSync, this.handleClientSync, this)
        NetworkManager.Instance.listenMsg(ApiMsgEnum.MsgServerSync, this.handleServerSync, this)
    }
    clearGame() {
        EventManager.Instance.off(EventEnum.ClientSync, this.handleClientSync, this)
        NetworkManager.Instance.unlistenMsg(ApiMsgEnum.MsgServerSync, this.handleServerSync, this)
        DataManager.Instance.stage = this.stage = this.node.getChildByName("Stage");
        this.ui = this.node.getChildByName("UI");
        this.stage.destroyAllChildren();
    }


    async connectServer() {

        if (!(await NetworkManager.Instance.connect().catch(() => false))) {

            await new Promise((rs) => setTimeout(rs, 2000))
            await this.connectServer();
        }
    }


    async loadRes() {
        const list = [];

        for (const type in PrefabPathEnum) {
            const p = ResourceManager.Instance.loadRes(PrefabPathEnum[type], Prefab).then((prefab) => {
                DataManager.Instance.prefabMap.set(type, prefab);
            })
            list.push(p);

        }


        for (const type in TexturePathEnum) {
            const p = ResourceManager.Instance.loadDir(TexturePathEnum[type], SpriteFrame).then((spriteFrames) => {
                DataManager.Instance.textureMap.set(type, spriteFrames);
            })
            list.push(p);

        }


        await Promise.all(list);

    }
    initMap() {
        //const prefab = DataManager.Instance.prefabMap.get(EntityTypeEnum.Map);

        const prefab = DataManager.Instance.prefabMap.get("Map");

        const map = instantiate(prefab);
        map.setParent(this.stage);
    }

    update(dt: number) {
        if (!this.shouldUpdate) {
            return;
        }
        this.render();
        this.tick(dt);
    }

    tick(dt: number) {
        this.tickActor(dt);

        DataManager.Instance.ApplyInput({
            type: InputTypeEnum.TimePast,
            dt,

        })

    }

    tickActor(dt: number) {
        for (const data of DataManager.Instance.state.actors) {
            const { id } = data;
            let am = DataManager.Instance.actorMap.get(data.id);
            am.tick(dt);

        }
    };

    render() {
        this.renderActor();
        this.renderBullet();
    }

    async renderActor() {

        for (const data of DataManager.Instance.state.actors) {
            const { id, type } = data;
            let am = DataManager.Instance.actorMap.get(data.id);
            if (!am) {

                const prefab = DataManager.Instance.prefabMap.get(type);
                const actor = instantiate(prefab);
                actor.setParent(this.stage);
                am = actor.addComponent(ActorManager);
                DataManager.Instance.actorMap.set(data.id, am);
                am.init(data);
            } else {
                am.render(data);
            }
        }
    }


    renderBullet() {

        for (const data of DataManager.Instance.state.bullets) {
            const { id, type } = data;
            let bm = DataManager.Instance.bulletMap.get(id);
            if (!bm) {
                const bullet = ObjectPoolManager.Instance.get(type)
                bm = bullet.getComponent(BulletManager) || bullet.addComponent(BulletManager);
                DataManager.Instance.bulletMap.set(data.id, bm);
                bm.init(data);
            } else {
                bm.render(data);
            }
        }
    }


    handleClientSync(input: IClientInput) {
        const msg = {
            input,
            frameId: DataManager.Instance.frameId++,
        }
        NetworkManager.Instance.sendMsg(ApiMsgEnum.MsgClientSync, msg)
    }

    handleServerSync({ inputs }: IMsgServerSync) {

        for (const input of inputs) {
            DataManager.Instance.ApplyInput(input)
        }
    }
}


